package com.gitee.wsl.net.ssdp.description.model.xml

import com.gitee.wsl.logger.Logger
import com.gitee.wsl.logger.info
import com.gitee.wsl.net.ssdp.description.xml.XmlElement
import kotlin.properties.Delegates

object ServiceList{
    /**
     * Service defined by a UPnP Forum working committee. If UPnP vendor differentiates device by adding additional,
     * standard UPnP services, repeated once for each additional service
     * @param serviceType   - UPnP service type. Shall not contain a hash character (#, 23 Hex in UTF-8). Single URI.
     *                          For standard service types defined by a UPnP Forum working committee, shall begin with
     *                          “urn:schemas-upnp-org:service:” followed by the standardized service type suffix, colon,
     *                          and an integer service version i.e. urn:schemas-upnp-org:device:serviceType:ver. The
     *                          highest supported version of the service type shall be specified.
     *                          For non-standard service types specified by UPnP vendors, shall begin with “urn:”,
     *                          followed by a Vendor Domain Name, followed by “:service:”, followed by a service type
     *                          suffix, colon, and an integer service version, i.e.,
     *                          “urn:domain-name:service:serviceType:ver”. Period characters in the Vendor Domain Name
     *                          shall be replaced with hyphens in accordance with RFC 2141. The highest supported
     *                          version of the service type shall be specified.
     *                          The service type suffix defined by a UPnP Forum working committee or specified by a UPnP
     *                          vendor shall be <= 64 characters, not counting the version suffix and separating colon.
     * @param serviceId     - Service identifier. Shall be unique within this device description. Single URI.
     *                          For standard services defined by a UPnP Forum working committee, shall begin with
     *                          “urn:upnp-org:serviceId:” followed by a service ID suffix i.e.
     *                          urn:upnp-org:serviceId:serviceID. If this instance of the specified service type (i.e.
     *                          the <serviceType> element above) corresponds to one of the services defined by the
     *                          specified device type (i.e. the <deviceType> element above), then the value of the service
     *                          ID suffix shall be the service ID defined by the device type for this instance of the
     *                          service. Otherwise, the value of the service ID suffix is vendor defined. (Note that
     *                          upnp-org is used instead of schemas-upnporg in this case because an XML schema is not
     *                          defined for each service ID.)
     *                          For non-standard services specified by UPnP vendors, shall begin with “urn:”, followed
     *                          by a Vendor Domain Name, followed by “:serviceId:”, followed by a service ID suffix,
     *                          i.e., “urn:domainname:serviceId:serviceID”. If this instance of the specified service type
     *                          (i.e. the <serviceType> element above) corresponds to one of the services defined by the
     *                          specified device type (i.e. the <deviceType> element above), then the value of the
     *                          service ID suffix shall be the service ID defined by the device type for this instance
     *                          of the service.
     *                          Period characters in the Vendor Domain Name shall be replaced with hyphens in accordance
     *                          with RFC 2141. The service ID suffix defined by a UPnP Forum working committee or
     *                          specified by a UPnP vendor shall be <= 64 characters.
     * @param scpdUrl       - URL for service description. (See clause 2.5, “Service description” below.) shall be
     *                          relative to the URL at which the device description is located in accordance with
     *                          clause 5 of RFC 3986. Specified by UPnP vendor. Single URL
     * @param controlUrl    - URL for control (see clause 3, “Control”). shall be relative to the URL at which the
     *                          device description is located in accordance with clause 5 of RFC 3986. Specified by UPnP
     *                          vendor. Single URL.
     * @param eventSubUrl   - URL for eventing (see clause 4, “Eventing”). shall be relative to the URL at which the
     *                          device description is located in accordance with clause 5 of RFC 3986. shall be unique
     *                          within the device; any two services shall not have the same URL for eventing. If the
     *                          service has no evented variables, this element shall be present but shall be empty (i.e.,
     *                          <eventSubURL></eventSubURL>.) Specified by UPnP vendor. Single URL.
     */
    data class Service(
        val serviceType: String,
        val serviceId: String,
        val scpdUrl: String,
        val controlUrl: String,
        val eventSubUrl: String
    ){
        /**
         * Facilitates flexible deserialization and conditional validation
         */
        companion object {
            fun fromXml(xml: XmlElement): Service {
                if(xml.tag != "service"){
                    throw IllegalArgumentException("Unexpected element ${xml.tag} in ServiceList")
                }
                var serviceTypeS by Delegates.notNull<String>()
                var serviceIdS by Delegates.notNull<String>()
                var scpdUrlS by Delegates.notNull<String>()
                var controlUrlS by Delegates.notNull<String>()
                var eventSubUrlS by Delegates.notNull<String>()

                xml.children?.forEach {
                    when(it.tag){
                        "serviceType" -> serviceTypeS = it.get()
                        "serviceId" -> serviceIdS = it.get()
                        "SCPDURL" -> scpdUrlS = it.get()
                        "controlURL" -> controlUrlS = it.get()
                        "eventSubURL" -> eventSubUrlS = it.get()
                        else -> Logger.info("Unexpected tag ${it.tag}")
                    }
                }
                return Service(serviceTypeS, serviceIdS, scpdUrlS, controlUrlS, eventSubUrlS)
            }
        }
    }

    fun fromXml(xml: XmlElement): List<Service> = xml.children?.map(Service::fromXml) ?: emptyList()
}
